package com.yingjia.yingjiauniversity.thread;

import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * <线程池获取>
 *
 * @author: guoxiangxun
 * @date: 17-1-19 下午5:47
 * @version: v1.0
 */
public class UtilThreadPool {

    public static final String DEFAULT = "application";
    public static final String UNLIMITED = "unlimited";

    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    private static final int KEEP_ALIVE = 1;

    private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(128);

    private static Map<String, ExecutorService> executorMap = new ConcurrentHashMap<String, ExecutorService>();

    static {
        newAndCacheCachedThreadPool(DEFAULT);
        newAndCacheCachedThreadPool(UNLIMITED);
    }

    /**
     * Gets thread executor.
     *
     * @param name the name
     * @return the thread executor
     */
    public static Executor getThreadExecutor(String name) {
        if (isCached(name)) {
            return executorMap.get(name);
        }
        return Executors.newCachedThreadPool();
    }

    /**
     * <remove executor>
     *
     * @param name the name
     * @return the executor
     * @author: guoxiangxun
     * @date: Jan 19, 2017 8:24:28 PM
     * @version: v1.0
     */
    public static Executor removeThreadExecutor(String name) {
        ExecutorService executorService = executorMap.remove(name);
        if (executorService != null) {
            executorService.shutdown();
        }
        return executorService;
    }


    public static ExecutorService newAndCachePerformanceThreadPool(String name) {
        if (isCached(name)) {
            return null;
        }
        ExecutorService executorService = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                TimeUnit.SECONDS, sPoolWorkQueue, new UtilThreadFactory(name));
        cacheExecutorService(name, executorService);
        return executorService;
    }


    public static ExecutorService newAndCacheFixedThreadPool(String name, int nThreads) {
        if (isCached(name)) {
            return null;
        }
        ExecutorService executorService = Executors.newFixedThreadPool(nThreads, new UtilThreadFactory(name));
        cacheExecutorService(name, executorService);
        return executorService;
    }


    public static ExecutorService newAndCacheFixedThreadPool(String name, int nThreads, ThreadFactory threadFactory) {
        if (isCached(name)) {
            return null;
        }
        ExecutorService executorService = Executors.newFixedThreadPool(nThreads, threadFactory);
        cacheExecutorService(name, executorService);
        return executorService;
    }

    public static ExecutorService newAndCacheSingleThreadExecutor(String name) {
        if (isCached(name)) {
            return null;
        }
        ExecutorService executorService = Executors.newSingleThreadExecutor(new UtilThreadFactory(name));
        cacheExecutorService(name, executorService);
        return executorService;
    }

    public static ExecutorService newAndCacheSingleThreadExecutor(String name, ThreadFactory threadFactory) {
        if (isCached(name)) {
            return null;
        }
        ExecutorService executorService = Executors.newSingleThreadExecutor(threadFactory);
        cacheExecutorService(name, executorService);
        return executorService;
    }

    public static ExecutorService newAndCacheCachedThreadPool(String name) {
        if (isCached(name)) {
            return null;
        }
        ExecutorService executorService = Executors.newCachedThreadPool(new UtilThreadFactory(name));
        cacheExecutorService(name, executorService);
        return executorService;
    }

    public static ExecutorService newAndCacheCachedThreadPool(String name, ThreadFactory threadFactory) {
        if (isCached(name)) {
            return null;
        }
        ExecutorService executorService = Executors.newCachedThreadPool(threadFactory);
        cacheExecutorService(name, executorService);
        return executorService;
    }

    public static ScheduledExecutorService newAndCacheSingleThreadScheduledExecutor(String name) {
        if (isCached(name)) {
            return null;
        }
        ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(new UtilThreadFactory(name));
        cacheExecutorService(name, executorService);
        return executorService;
    }

    public static ScheduledExecutorService newAndCacheSingleThreadScheduledExecutor(String name, ThreadFactory threadFactory) {
        if (isCached(name)) {
            return null;
        }
        ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(threadFactory);
        cacheExecutorService(name, executorService);
        return executorService;
    }

    public static ScheduledExecutorService newAndCacheScheduledThreadPool(String name, int corePoolSize) {
        if (isCached(name)) {
            return null;
        }
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(corePoolSize, new UtilThreadFactory(name));
        return scheduledExecutorService;
    }

    public static ScheduledExecutorService newAndCacheScheduledThreadPool(String name, int corePoolSize, ThreadFactory threadFactory) {
        if (isCached(name)) {
            return null;
        }
        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(corePoolSize, threadFactory);
        cacheExecutorService(name, executorService);
        return executorService;
    }

    /**
     * <assert is cached>
     *
     * @param name the name
     * @return the boolean
     * @author: guoxiangxun
     * @date: Jan 19, 2017 8:22:07 PM
     * @version: v1.0
     */
    private static boolean isCached(String name) {
        Executor executor = executorMap.get(name);
        if (executor == null) {
            return false;
        }
        return true;
    }


    /**
     * <cache executorService>
     *
     * @param name     the name
     * @param executor the executor
     * @author: guoxiangxun
     * @date: Jan 19, 2017 8:22:10 PM
     * @version: v1.0
     */
    private static void cacheExecutorService(String name, ExecutorService executor) {
        assert executor == null;

        if (executor != null) {
            executorMap.put(name, executor);
        }
    }
}
